package q1.project.log;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Optional;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import q1.project.common.context.TenantContext;

/**
 * 操作日志切面 拦截 @OperationLog 注解，自动记录操作日志
 *
 * @author Q1 Team
 * @version 1.0
 */
@Aspect
@Component
public class OperationLogAspect {

  private static final Logger log = LoggerFactory.getLogger(OperationLogAspect.class);

  private final Optional<OperationLogService> operationLogService;
  private final ObjectMapper objectMapper = new ObjectMapper();

  /** 构造函数，用于验证Bean是否被创建 */
  public OperationLogAspect(Optional<OperationLogService> operationLogService) {
    this.operationLogService = operationLogService;
    log.info("操作日志切面已初始化");
  }

  /** 初始化后检查服务是否注入 */
  @jakarta.annotation.PostConstruct
  public void init() {
    log.info("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    log.info("操作日志切面初始化检查:");
    log.info("  - 切面Bean已创建: {}", this.getClass().getName());
    if (operationLogService == null) {
      log.error("  ❌ OperationLogService 未注入！操作日志将无法保存到数据库。");
      log.error("  可能的原因:");
      log.error("    1. OperationLogServiceImpl 没有被 Spring 扫描到");
      log.error("    2. 包扫描路径配置不正确");
      log.error("    3. Service 注解缺失");
    } else {
      log.info("  ✓ OperationLogService 已注入: {}", operationLogService.getClass().getName());
      log.info("  ✓ 操作日志功能正常");
    }
    log.info("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
  }

  @Around("@annotation(q1.project.log.OperationLog)")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    long startTime = System.currentTimeMillis();

    // 检查切面是否被调用
    log.info("操作日志切面被触发: method={}", joinPoint.getSignature().toShortString());

    OperationLogEntity logEntity = new OperationLogEntity();
    HttpServletRequest request = getHttpServletRequest();

    try {
      // 获取注解信息
      MethodSignature signature = (MethodSignature) joinPoint.getSignature();
      Method method = signature.getMethod();
      OperationLog annotation = method.getAnnotation(OperationLog.class);

      // 填充基本信息
      logEntity.setModule(annotation.module());
      logEntity.setType(annotation.type());
      logEntity.setDescription(annotation.description());
      logEntity.setMethod(method.getDeclaringClass().getName() + "." + method.getName());

      // 填充租户和用户信息
      logEntity.setTenantId(TenantContext.getTenantId());
      // TODO: 从 JWT Token 获取用户信息
      // if (isLogin()) {
      //   logEntity.setUserId(getCurrentUserId());
      //   logEntity.setUsername(getCurrentUsername());
      // }

      // 填充请求信息
      if (request != null) {
        logEntity.setUrl(request.getRequestURI());
        logEntity.setIp(getIpAddress(request));
        logEntity.setBrowser(request.getHeader("User-Agent"));

        // 保存请求参数
        if (annotation.saveParams()) {
          Object[] args = joinPoint.getArgs();
          if (args != null && args.length > 0) {
            logEntity.setParams(objectMapper.writeValueAsString(args));
          }
        }
      }

      // 执行目标方法
      Object result = joinPoint.proceed();

      // 保存响应结果
      if (annotation.saveResult() && result != null) {
        logEntity.setResult(objectMapper.writeValueAsString(result));
      }

      logEntity.setSuccess(true);

      // 记录日志到控制台
      log.info(
          "【操作日志】模块={}, 类型={}, 描述={}, 用户={}, IP={}, 耗时={}ms",
          annotation.module(),
          annotation.type(),
          annotation.description(),
          logEntity.getUserId(),
          logEntity.getIp(),
          System.currentTimeMillis() - startTime);

      return result;

    } catch (Throwable e) {
      logEntity.setSuccess(false);
      logEntity.setErrorMsg(e.getMessage());

      log.error("【操作日志】操作失败: {}", e.getMessage(), e);
      throw e;

    } finally {
      // 计算执行时长
      logEntity.setExecutionTime(System.currentTimeMillis() - startTime);

      // 异步保存日志到数据库
      if (operationLogService != null) {
        try {
          log.info(
              "准备保存操作日志: module={}, type={}, description={}, tenantId={}, userId={}, thread={}",
              logEntity.getModule(),
              logEntity.getType(),
              logEntity.getDescription(),
              logEntity.getTenantId(),
              logEntity.getUserId(),
              Thread.currentThread().getName());

          // 记录日志实体信息（调试用）
          log.debug(
              "操作日志实体详情: id={}, module={}, type={}, description={}, tenantId={}, userId={}, url={}, ip={}",
              logEntity.getId(),
              logEntity.getModule(),
              logEntity.getType(),
              logEntity.getDescription(),
              logEntity.getTenantId(),
              logEntity.getUserId(),
              logEntity.getUrl(),
              logEntity.getIp());

          operationLogService.ifPresent(service -> service.saveAsync(logEntity));
          log.info(
              "操作日志已提交异步保存（调用完成，等待异步执行）: module={}, type={}, description={}, thread={}",
              logEntity.getModule(),
              logEntity.getType(),
              logEntity.getDescription(),
              Thread.currentThread().getName());
        } catch (Exception e) {
          log.error(
              "调用异步保存操作日志失败: module={}, type={}, description={}, error={}",
              logEntity.getModule(),
              logEntity.getType(),
              logEntity.getDescription(),
              e.getMessage(),
              e);
        }
      } else {
        log.error(
            "OperationLogService 未注入，无法保存操作日志: module={}, type={}, description={}",
            logEntity.getModule(),
            logEntity.getType(),
            logEntity.getDescription());
      }
    }
  }

  /** 获取HttpServletRequest */
  private HttpServletRequest getHttpServletRequest() {
    try {
      ServletRequestAttributes attributes =
          (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      return attributes != null ? attributes.getRequest() : null;
    } catch (Exception e) {
      return null;
    }
  }

  /** 获取客户端IP地址 */
  private String getIpAddress(HttpServletRequest request) {
    String ip = request.getHeader("X-Forwarded-For");
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("X-Real-IP");
    }
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getRemoteAddr();
    }
    // 处理多级代理的情况
    if (ip != null && ip.contains(",")) {
      ip = ip.split(",")[0].trim();
    }
    return ip;
  }
}
